package problems.maze20;

import globals.CentralStatics;
import problems.TransitionFunction;

public class Maze20Transitions implements TransitionFunction<Integer,Integer>{

	private Walls walls;
	
	private static Maze20Transitions trans = null;
	
	public Maze20Transitions(){
		walls = Walls.theWalls();
	}
	
	@Override
	public double probabilityOfTransition(Integer state, Integer action,
			Integer statePrime) {
		double[] vec = this.probabilityVector(state, action);
		return vec[statePrime.intValue()];
	}

	@Override
	public double[] probabilityVector(Integer state, Integer action) {
		double[] vec = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
		int n = state.intValue()+5;
		int e = state.intValue()+1;
		int s = state.intValue()-5;
		int w = state.intValue()-1;
		int curr= state.intValue();
		if(state.intValue()==7){//terminal state
			vec[7] = 1;
			return vec;
		}
		if(action.intValue()==Maze20Actions.SENSEEW.intValue() || 
				action.intValue()==Maze20Actions.SENSENS.intValue() ){
			//no movement
			vec[state.intValue()]=1;
			return vec;
		}
		if(action.intValue()==Maze20Actions.NORTH.intValue()){
			//north:
			if(walls.north(curr)){
				vec[curr] += 0.7;
			} else {
				vec[n] += 0.7;
			}
			//east:
			if(walls.east(curr)){
				vec[curr] += 0.15;
			} else {
				vec[e] += 0.15;
			}
			//west:
			if(walls.west(curr)){
				vec[curr] += 0.15;
			} else {
				vec[w] += 0.15;
			}
		}
		if(action.intValue()==Maze20Actions.EAST.intValue()){
			//north:
			if(walls.east(curr)){
				vec[curr] += 0.7;
			} else {
				vec[e] += 0.7;
			}
			//north:
			if(walls.north(curr)){
				vec[curr] += 0.15;
			} else {
				vec[n] += 0.15;
			}
			//south:
			if(walls.south(curr)){
				vec[curr] += 0.15;
			} else {
				vec[s] += 0.15;
			}
		}
		if(action.intValue()==Maze20Actions.SOUTH.intValue()){
			//north:
			if(walls.south(curr)){
				vec[curr] += 0.7;
			} else {
				vec[s] += 0.7;
			}
			//east:
			if(walls.east(curr)){
				vec[curr] += 0.15;
			} else {
				vec[e] += 0.15;
			}
			//west:
			if(walls.west(curr)){
				vec[curr] += 0.15;
			} else {
				vec[w] += 0.15;
			}
		}
		if(action.intValue()==Maze20Actions.WEST.intValue()){
			//north:
			if(walls.west(curr)){
				vec[curr] += 0.7;
			} else {
				vec[w] += 0.7;
			}
			//north:
			if(walls.north(curr)){
				vec[curr] += 0.15;
			} else {
				vec[n] += 0.15;
			}
			//south:
			if(walls.south(curr)){
				vec[curr] += 0.15;
			} else {
				vec[s] += 0.15;
			}
		}
		return vec;
	}

	@Override
	public Integer nextState(Integer currentState, Integer action) {
		double r = CentralStatics.getCentralRandom().nextDouble();
		double[] vec = this.probabilityVector(currentState, action);
		double prob = 0.0;
		Maze20States s = Maze20States.getStates();
		for(int i=0; i<vec.length; i++){
			prob += vec[i];
			if(r<=prob){
				return s.stateIdentifier(i);
			}
		}
		return null;
	}
	
	public static Maze20Transitions getTransitions(){
		if(Maze20Transitions.trans ==null){
			Maze20Transitions.trans = new Maze20Transitions();
		}
		return Maze20Transitions.trans;
	}

}
